package lib;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;

/** Maintain a numpy array of elements, and another of values.
 *  These are ordered by element, and support fast insertion and
 *  search.  Insertion of a duplicate element should update the value
 *  of the element with the max of that existing and inserted.
 */
public class SortedArray {
	ArrayList<Couple<String, String>> blasthits;
	ArrayList<Double> bitscores;
	static int p;
	
	public SortedArray(String fileName) {
		try {
			File file = new File(fileName);
			int size = (int) file.length();
			byte[] data = new byte[size];		
			
			FileInputStream inputStream = new FileInputStream(file);
			inputStream.read(data, 0, size);			//Read entire file to memory for fast processing
			inputStream.close();
			
			String line = new String(readLine(data, size));
			int totalLines = size/line.length();
			blasthits = new ArrayList<Couple<String, String>>((int)(totalLines/1.2));
			bitscores = new ArrayList<Double>((int)(totalLines/1.2));
			
			int lineRead = 0;
			for(p=0; p<size; p++) {
				line = new String(readLine(data, size));
				lineRead++;
				if(lineRead % 10000 == 0)
					System.out.println(lineRead + " lines read.");
				String[] strArr = line.split("\t");
				if(strArr.length < 3)
					strArr = line.split(" ");
				if(strArr.length < 3)
					throw new IOException(); 
				Double bitscore = Double.parseDouble(strArr[2]);
				int index1 = blasthits.indexOf(new Couple<String,String>(strArr[0], strArr[1]));
				int index2 = blasthits.indexOf(new Couple<String,String>(strArr[1], strArr[0]));
				if(index1 == -1 && index2 == -1) {
					blasthits.add(new Couple<String,String>(strArr[0], strArr[1]));
					bitscores.add(bitscore);
				} else if(index1 > -1 && bitscores.get(index1) > bitscore) {
					blasthits.set(index1, new Couple<String,String>(strArr[0], strArr[1]));
					bitscores.set(index1, bitscore);
				} else if(index2 > -1 && bitscores.get(index2) > bitscore) {
					blasthits.set(index2, new Couple<String,String>(strArr[0], strArr[1]));
					bitscores.set(index2, bitscore);
				}
			}
		} catch (FileNotFoundException e) {
			System.out.println("Error in data file. File not found");
			System.exit(-1);
		} catch (IOException e) {
			System.out.println("Error in data file. File format not a three column separated by tabs or spaces.");
			System.exit(-2);
		}
		
	}
	
	private static byte[] readLine(byte[] data, int sizeofFile) {
		/* ******************** FUNCTION VARIABLES ******************************** */
		byte[] 				line;
		int 				size;
		/* ******************** VARIABLE INITIALIZERS ***************************** */
		size 				= 0;
		
		/* ******************** FUNCTION BODY ************************************* */
		while(p < sizeofFile && data[p] != '\n') {
			p++;
			size++;
		}
		line = new byte[size];
		System.arraycopy(data, p-size, line, 0, size);
		return line;
		/* ******************** END OF FUNCTION *********************************** */
	}
	
	public void displayData() {
		for(int i = 0; i < blasthits.size(); i++) 
			System.out.println(blasthits.get(i).first + "\t" + blasthits.get(i).second + "\t" + bitscores.get(i));
	}
	
	public ArrayList<Couple<String, String>> getBlastHits() {
		return blasthits;
	}
	
	public ArrayList<Double> getBitScores() {
		return bitscores;
	}
}
